/**
 * Copyright (C) 2008+ Spark Zheng
 *
 * @file	src/except.c
 * @brief
 *      Exception Module (implement from prototype in book < C I&I >):
 *      Work as follow sentences:
 *
 *	do {
 *		create and push an except_frame;
 *
 *		if (first return from setjmp) {
 *			S;
 *		} else if (exception is e1) {
 *			S1;
 *		} else if (exception is e2) {
 *			S2;
 *			......
 *		} else if (exception is eN) {
 *			SN;
 *		} else {
 *			S0;
 *		}
 *
 *		if (an exception occurred and wasn't handled)
 *			RERAISE();
 *	} while (0);
 *
 *      TRY-EXCEPT  /  TRY-FINALLY
 *
 * @see		dlib
 * @module      dlib
 *
 * @history
 *      version 0.0.1   Spark Zheng init except module
 */

#include <stdlib.h>
#include <stdio.h>
#include "except.h"

/**
 * Global var for recursive exception.
 * just worked in recursive exception, no side-effect.
 */
except_frame_t *except_stack = NULL;

/**
 * Global var for assert faild exception.
 * work in debug model
 */
const exception_t assert_faild = {
	.index = 'a',
	.msg = "assert failed.",
};

void except_raise(const exception_t *e, const char *file, int line)
{
	except_frame_t *es = except_stack;

	assert(e);

	if (es == NULL) {
		fprintf(stderr, "Exception: Uncaught exception.\n");

		if (e->msg != NULL)
			fprintf(stderr, "Exception[#%d]: %s.", e->index,
				e->msg);
		else
			fprintf(stderr, "Exception[#unknow]: 0x%p.", e);

		if (file && line > 0)
			fprintf(stderr, " raised at file %s, line %d\n", file,
				line);

		fprintf(stderr, "aborting...\n");
		fflush(stderr);
		abort();
	}

	es->exception = e;
	es->file = file;
	es->line = line;

	except_stack = es->prev;

	longjmp(es->env, EXCEPT_RAISED);

	return;
}
